package com.rednote.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rednote.common.UserContextHolder;
import com.rednote.entity.Posts;
import com.rednote.entity.UserLikes;
import com.rednote.entity.UserPostRating;
import com.rednote.entity.Users;
import com.rednote.entity.vo.AuthorVO;
import com.rednote.entity.vo.CommentVO;

import com.rednote.entity.vo.PostCardVO;
import com.rednote.entity.vo.PostVO;
import com.rednote.mapper.PostsMapper;
import com.rednote.mapper.UserLikesMapper;
import com.rednote.mapper.UserPostRatingMapper;
import com.rednote.mapper.UsersMapper;
import com.rednote.service.PostsService;
import com.rednote.service.UserCollectService;
import com.rednote.service.UserLikesService;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.similarity.UncenteredCosineSimilarity;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.*;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericPreference;
import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.Preference;
import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
/**
 * 用户帖子表(Posts)服务实现类
 *
 * @author yao suxuan
 * @since 2025-05-24 18:10:30
 */
@Service
public class PostsServiceImpl extends ServiceImpl<PostsMapper, Posts> implements PostsService {

    @Autowired
    private PostsMapper postMapper;
    @Autowired
    private CommentsServiceImpl commentsService;
    @Autowired
    private UsersMapper usersMapper;
    @Autowired
    private UserLikesService userLikesService;
    @Autowired
    private UserCollectService userCollectService;
    @Autowired
    private UserFollowServiceImpl userFollowService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserLikesMapper userLikesMapper;
    @Autowired
    private PostsMapper postsMapper;
    @Autowired
    private UserPostRatingMapper userPostRatingMapper;


    public PostVO getPostDetail(Integer postId, int page, int pageSize) throws JsonProcessingException {
        page = Math.max(page, 1);
        pageSize = Math.max(pageSize, 1);
        Posts post = postMapper.selectById(postId);
        if (post == null) {
            throw new RuntimeException("帖子不存在");
        }

        int totalComments = post.getCommentCount();//TODO:添加评论的时候修改总数
        // 计算总页数
        int totalPages = Math.max(1, (int) Math.ceil((double) totalComments / pageSize));
        // 判断页面是否超出最大页数
        if (page > totalPages) {
            throw new RuntimeException("页码超出范围，最大页码为 " + totalPages);
        }
        PostVO postDetail = new PostVO();
        // 获取发帖人
        AuthorVO authorVO = new AuthorVO();
        Users user = usersMapper.selectById(post.getUserId());
        authorVO.setId(user.getUserId());
        authorVO.setName(user.getUsername());
        authorVO.setImg(user.getAvatar());
        Integer currentUserId = UserContextHolder.getUserId();
        authorVO.setIsAuthor(Objects.equals(currentUserId, user.getUserId()));
        authorVO.setIsFollowed(userFollowService.isFollowed(user.getUserId()));
        postDetail.setAuthor(authorVO);
        // 构建 PostVO
        BeanUtils.copyProperties(post, postDetail);
        postDetail.setId(post.getPostId());
        // imageUrls (JSON字符串) -> imgs (List<String>)
        ObjectMapper objectMapper = new ObjectMapper();
        if (post.getVideoUrl() == null || post.getVideoUrl().isEmpty()) {
            // 无视频，解析图片数组
            List<String> imgs = objectMapper.readValue(post.getImageUrls(), new TypeReference<List<String>>() {});
            postDetail.setImgs(imgs);
        } else {
            // 有视频，只放视频 URL
            List<String> imgs = Collections.singletonList(post.getVideoUrl());
            // postDetail.setImgs(imgs);
            postDetail.setVideo(post.getVideoUrl());
        }
        //先从redis里读点赞数
        int likeCount = userLikesService.getLikeCount(postId, 0);
        if(likeCount<0) likeCount=0;
        postDetail.setLike(likeCount);

        postDetail.setFav(post.getCollectCount());
        if (post.getCreatedAt() != null) {
            String timeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(post.getCreatedAt());
            postDetail.setTime(timeStr);
        }
        // 处理标签，添加空值处理
        if (StringUtils.hasText(post.getTag())) {
            postDetail.setTags(Arrays.asList(post.getTag().split(",")));
        } else {
            postDetail.setTags(Collections.emptyList());
        }
        IPage<CommentVO> comments= commentsService.getCommentsByPostId(postId,post.getUserId(), page, pageSize);
        postDetail.setComments(comments.getRecords());
        postDetail.setIsLike(userLikesService.getIsLike(postId,0));
        postDetail.setIsFav(userCollectService.isCollected(postId));
        // 设置浏览记录
        redisTemplate.opsForValue().setBit("user:viewed:" + currentUserId, postId, true);
        return postDetail;
    }

    public void removePostById(Integer id) {
        if(id == null) {
            throw new IllegalArgumentException("帖子ID不能为空");
        }
        Posts post= postMapper.selectById(id);
        if(post == null) {
            throw new RuntimeException("帖子不存在");
        }
        Integer userId= UserContextHolder.getUserId();
        if(userId == null || !userId.equals(post.getUserId())) {
            throw new RuntimeException("无权限删除此帖子");
        }
        postMapper.deleteById(id);
        // 删除相关评论
        commentsService.removeCommentsByPostId(id);
    }

    public List<PostCardVO> recommend(int cursor, int pageSize) {
        int userId = UserContextHolder.getUserId();
        int batchSize = 100;
        String[] zsets = {"hot:24h", "hot:7d", "hot:all"};

        Set<Integer> resultSet = new LinkedHashSet<>(); // 保证顺序 + 去重

        for (String zset : zsets) {
            int start = cursor;

            while (resultSet.size() < pageSize) {
                Set<String> batch = redisTemplate.opsForZSet().reverseRange(zset, start, start + batchSize - 1);
                if (batch == null || batch.isEmpty()) break;

                for (String postIdStr : batch) {
                    int postId = Integer.parseInt(postIdStr);

                    // 判断是否已浏览 或 已经加入推荐列表
                    if (!Boolean.TRUE.equals(redisTemplate.opsForValue().getBit("user:viewed:" + userId, postId))
                            && !resultSet.contains(postId)) {
                        resultSet.add(postId);
                    }

                    if (resultSet.size() >= pageSize) break;
                }

                start += batchSize;
            }

            if (resultSet.size() >= pageSize) break;
        }

        List<Integer> postIdList = new ArrayList<>(resultSet);

        // 查询数据库，保持推荐顺序一致（即根据 postIdList 的顺序排序）
        if (postIdList.isEmpty()) return new ArrayList<>();

        List<Posts> posts = postMapper.selectBatchIds(postIdList);
        Map<Integer, Posts> postMap = posts.stream().collect(Collectors.toMap(Posts::getPostId, p -> p));
        List<PostCardVO> postCardVOs = new ArrayList<>();
        System.out.println("查询到的帖子数量: " + posts.size());

        for(Integer postId : postIdList) {
            Posts post = postMap.get(postId);
            PostCardVO vo = convertToCardVO(post);
            // 获取发帖人信息
            Users user = usersMapper.selectById(post.getUserId());
            if (user != null) {
                AuthorVO author = new AuthorVO();
                author.setId(user.getUserId());
                author.setName(user.getUsername());
                author.setImg(user.getAvatar());
                author.setIsAuthor(Objects.equals(UserContextHolder.getUserId(), user.getUserId()));
                author.setIsFollowed(userFollowService.isFollowed(user.getUserId()));
                vo.setAuthor(author);
            }
            postCardVOs.add(vo);

        }
        return postCardVOs;
    }

    public PostCardVO convertToCardVO(Posts post) {
        PostCardVO vo = new PostCardVO();
        vo.setId(post.getPostId());

        // 从 imageUrls JSON 字符串中获取所有图片 URL
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            if (post.getVideoUrl() == null || post.getVideoUrl().isEmpty()) {
                // 无视频时，解析所有图片URL
                List<String> imageUrls = objectMapper.readValue(post.getImageUrls(), new TypeReference<List<String>>() {});
                vo.setImg(imageUrls.isEmpty() ? null : imageUrls.get(0)); // 设置第一张图为封面
            } else {
                // 有视频时，使用视频封面
                vo.setImg(post.getCoverUrl());
            }
        } catch (JsonProcessingException e) {
            vo.setImg(null);
        }

        vo.setIsLike(userLikesService.getIsLike(post.getPostId(),0));
        vo.setIsFav(userCollectService.isCollected(post.getPostId()));
        vo.setTitle(post.getTitle());
        vo.setLike(post.getLikeCount());
        vo.setVideo(post.getVideoUrl());
        vo.setDuration(post.getDuration());
        vo.setType(post.getVideoUrl() != null ? "video" : "image");
        vo.setIsPrivate(false);
        // 处理标签
        if (StringUtils.hasText(post.getTag())) {
            List<String> tags = Arrays.asList(post.getTag().split(","));
            vo.setTags(tags);
        } else {
            vo.setTags(Collections.emptyList());
        }

        return vo;
    }

    @Override
    public Page<PostCardVO> searchPosts(String keyword, Integer page, Integer limit, String tag) {
        System.out.println("搜索帖子: keyword=" + keyword + ", page=" + page + ", limit=" + limit + ", tag=" + tag);
        // 创建查询条件
        LambdaQueryWrapper<Posts> queryWrapper = new LambdaQueryWrapper<>();

        // 添加关键词搜索条件（标题或内容包含关键词）
        if (StringUtils.hasText(keyword)) {
            queryWrapper.and(w -> w.like(Posts::getTitle, "%" + keyword + "%")
                    .or()
                    .like(Posts::getContent, "%" + keyword + "%"));
        }

        // 添加标签筛选条件
        if (StringUtils.hasText(tag)) {
            queryWrapper.like(Posts::getTag, tag);
        }

        // 按创建时间倒序排序
        queryWrapper.orderByDesc(Posts::getCreatedAt);

        // 执行分页查询
        Page<Posts> postsPage = new Page<>(page, limit);
        Page<Posts> result = this.page(postsPage, queryWrapper);
        
        System.out.println("查询结果数量: " + result.getTotal());
        System.out.println("当前页记录数: " + result.getRecords().size());
        
        // 转换为PostCardVO，增加空值处理
        Page<PostCardVO> voPage = new Page<>(page, limit, result.getTotal());
        List<PostCardVO> voList = new ArrayList<>();

        for (Posts post : result.getRecords()) {
            try {
                PostCardVO vo = new PostCardVO();
                // 设置基本信息，处理可能的空值
                vo.setId(post.getPostId());
                vo.setTitle(post.getTitle() != null ? post.getTitle() : "");
                vo.setLike(post.getLikeCount() != null ? post.getLikeCount() : 0);
                vo.setVideo(post.getVideoUrl());
                vo.setDuration(post.getDuration());
                vo.setType(post.getVideoUrl() != null ? "video" : "image");
                vo.setIsPrivate(false);
                vo.setIsLike(userLikesService.getIsLike(post.getPostId(), 0));
                vo.setIsFav(userCollectService.isCollected(post.getPostId()));
                // 处理图片URL，添加空值处理
                try {
                    if (post.getVideoUrl() != null && !post.getVideoUrl().isEmpty()) {
                        // 有视频时使用视频封面
                        vo.setImg(post.getCoverUrl());
                    } else if (StringUtils.hasText(post.getImageUrls())) {
                        // 无视频时处理图片
                        ObjectMapper objectMapper = new ObjectMapper();
                        List<String> imageUrls = objectMapper.readValue(post.getImageUrls(), new TypeReference<List<String>>() {});
                        vo.setImg(imageUrls != null && !imageUrls.isEmpty() ? imageUrls.get(0) : null);
                    }
                } catch (Exception e) {
                    System.out.println("处理图片URL失败: postId=" + post.getPostId() + ", error=" + e.getMessage());
                    vo.setImg(null);
                }

                // 处理标签，添加空值处理
                if (StringUtils.hasText(post.getTag())) {
                    vo.setTags(Arrays.asList(post.getTag().split(",")));
                } else {
                    vo.setTags(Collections.emptyList());
                }

                // 设置作者信息，添加空值处理
                Users user = usersMapper.selectById(post.getUserId());
                if (user != null) {
                    AuthorVO author = new AuthorVO();
                    author.setId(user.getUserId());
                    author.setName(user.getUsername() != null ? user.getUsername() : "");
                    author.setImg(user.getAvatar());
                    Integer currentUserId = UserContextHolder.getUserId();
                    author.setIsAuthor(Objects.equals(currentUserId, user.getUserId()));
                    author.setIsFollowed(userFollowService.isFollowed(user.getUserId()));
                    vo.setAuthor(author);
                }

                voList.add(vo);
            } catch (Exception e) {
                System.out.println("转换PostCardVO失败: postId=" + post.getPostId() + ", error=" + e.getMessage());
                // 继续处理下一条记录，不影响整体结果
                continue;
            }
        }

        voPage.setRecords(voList);
        return voPage;
    }

    private PostVO convertToVO(Posts post) {
        PostVO vo = new PostVO();
        BeanUtils.copyProperties(post, vo);
        // 这里可以添加其他需要的转换逻辑
        return vo;
    }

    public List<PostCardVO> getMyPosts(Integer userId, Integer page, Integer size) {
        // 创建分页对象
        Page<Posts> pageParam = new Page<>(page, size);
        // 创建查询条件
        LambdaQueryWrapper<Posts> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Posts::getUserId, userId)
                   .orderByDesc(Posts::getCreatedAt);
        List<PostCardVO> postCardVOs = new ArrayList<>();
        // 执行分页查询
        Page<Posts> posts=this.baseMapper.selectPage(pageParam, queryWrapper);
        for( Posts post : posts.getRecords()) {
            PostCardVO vo = convertToCardVO(post);
            // 获取发帖人信息
            Users user = usersMapper.selectById(post.getUserId());
            if (user != null) {
                AuthorVO author = new AuthorVO();
                author.setId(user.getUserId());
                author.setName(user.getUsername());
                author.setImg(user.getAvatar());
                author.setIsAuthor(Objects.equals(UserContextHolder.getUserId(), user.getUserId()));
                author.setIsFollowed(userFollowService.isFollowed(user.getUserId()));
                vo.setAuthor(author);
            }
            postCardVOs.add(vo);
        }
        return postCardVOs;
    }

    public Page<PostCardVO> getMyLikedPosts(Integer userId, Integer page, Integer size) {
        // 查询该用户点赞过的帖子ID列表
        List<Integer> likedPostIds = userLikesMapper.selectObjs(
                new QueryWrapper<UserLikes>().select("target_id").eq("user_id", userId)
        ).stream().map(obj -> (Integer) obj).collect(Collectors.toList());

        if (likedPostIds.isEmpty()) {
            return new Page<>(page, size); // 返回空分页结果
        }

        // 构建分页查询帖子内容
        Page<Posts> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Posts> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Posts::getPostId, likedPostIds)
                .orderByDesc(Posts::getCreatedAt); // 时间倒序

        Page<Posts> postPage = postsMapper.selectPage(pageParam, queryWrapper);

        // 将 Posts 转换为 PostCardVO
        List<PostCardVO> voList = postPage.getRecords().stream()
                .map(this::convertToCardVO)
                .collect(Collectors.toList());

        // 构建新的 Page<PostCardVO>
        Page<PostCardVO> voPage = new Page<>();
        voPage.setCurrent(postPage.getCurrent());
        voPage.setSize(postPage.getSize());
        voPage.setTotal(postPage.getTotal());
        voPage.setPages(postPage.getPages());
        voPage.setRecords(voList);

        return voPage;
    }

    /**
     * 首页帖子推荐相似度算法
     * 基于用户浏览记录和点赞记录，推荐相似帖子
     */
    @Override
    public Page<PostCardVO> recommendSimilarPosts(Integer userId, Integer page, Integer size) throws TasteException {

        List<UserPostRating> userList = userPostRatingMapper.selectList(null);
        //创建数据模型
        DataModel dataModel = this.createDataModel(userList);
        //获取用户相似程度
        UserSimilarity similarity = new UncenteredCosineSimilarity(dataModel);
        // 计算并输出每两个用户 ID 之间的相似度
        // 获取所有唯一的用户 ID
        Set<Long> uniqueUserIds = userList.stream()
                .map(UserPostRating::getUserId)
                .collect(Collectors.toSet());
        List<Long> userIds = new ArrayList<>(uniqueUserIds);
        System.out.println("用户数量: " + userIds.size());
        // 用于记录已经计算过的用户 ID 对
        Set<String> computedPairs = new HashSet<>();
        for (int i = 0; i < userIds.size(); i++) {
            for (int j = i + 1; j < userIds.size(); j++) {
                long userId1 = userIds.get(i);
                long userId2 = userIds.get(j);
                // 生成唯一的键来表示用户 ID 对
                String pairKey = userId1 < userId2 ? userId1 + "-" + userId2 : userId2 + "-" + userId1;
                if (!computedPairs.contains(pairKey)) {
                    double similarityValue = similarity.userSimilarity(userId1, userId2);
                    System.out.printf("用户 %d 与用户 %d 的相似度: %.4f%n", userId1, userId2, similarityValue);
                    computedPairs.add(pairKey);
                }
            }
        }
        //获取用户邻居
        UserNeighborhood userNeighborhood = new NearestNUserNeighborhood(2, similarity, dataModel);

        //构建推荐器
        Recommender recommender = new GenericUserBasedRecommender(dataModel, userNeighborhood, similarity);
        //推荐2个
        List<RecommendedItem> recommendedItems = recommender.recommend(userId.longValue(), Math.toIntExact(postsMapper.selectCount(null)));
        if (recommendedItems == null || recommendedItems.isEmpty()) {
            System.out.println("推荐系统返回空结果，可能原因：");
            System.out.println("- 数据不足（当前用户数：" + dataModel.getNumUsers() + ")");
            System.out.println("- 目标用户无相似用户");
            return new Page<>(page, size);
        }
        // 4. 提取推荐的帖子ID
        List<Long> itemIds = recommendedItems.stream()
                .map(RecommendedItem::getItemID)
                .collect(Collectors.toList());
        if (itemIds.isEmpty()) {
            return new Page<>(page, size); // 返回空分页结果
        }


        // 5. 使用MyBatis-Plus分页查询帖子详情
        Page<Posts> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Posts> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Posts::getPostId, itemIds)
                .orderByDesc(Posts::getCreatedAt); // 按时间倒序

        Page<Posts> postPage = postsMapper.selectPage(pageParam, queryWrapper);

        // 6. 转换为VO并添加作者信息
        List<PostCardVO> voList = new ArrayList<>();
        for (Posts post : postPage.getRecords()) {
            PostCardVO vo = convertToCardVO(post);
            // 获取发帖人信息
            Users user = usersMapper.selectById(post.getUserId());
            if (user != null) {
                AuthorVO author = new AuthorVO();
                author.setId(user.getUserId());
                author.setName(user.getUsername());
                author.setImg(user.getAvatar());
                author.setIsAuthor(Objects.equals(UserContextHolder.getUserId(), user.getUserId()));
                author.setIsFollowed(userFollowService.isFollowed(user.getUserId()));
                vo.setAuthor(author);
            }
            voList.add(vo);
        }

        // 7. 构建分页结果
        Page<PostCardVO> voPage = new Page<>();
        voPage.setCurrent(postPage.getCurrent());
        voPage.setSize(postPage.getSize());
        voPage.setTotal(postPage.getTotal());
        voPage.setPages(postPage.getPages());
        voPage.setRecords(voList);

        return voPage;
    }

//    @Override
//    public List<PostCardVO> recommendSimilarPosts(Integer userId, Integer page, Integer size) throws TasteException {
//
//        List<UserPostRating> userList = userPostRatingMapper.selectList(null);
//        //创建数据模型
//        DataModel dataModel = this.createDataModel(userList);
//        //获取用户相似程度
//        UserSimilarity similarity = new UncenteredCosineSimilarity(dataModel);
//        // 计算并输出每两个用户 ID 之间的相似度
//        // 获取所有唯一的用户 ID
//        Set<Long> uniqueUserIds = userList.stream()
//                .map(UserPostRating::getUserId)
//                .collect(Collectors.toSet());
//        List<Long> userIds = new ArrayList<>(uniqueUserIds);
//        // 用于记录已经计算过的用户 ID 对
//        Set<String> computedPairs = new HashSet<>();
//        for (int i = 0; i < userIds.size(); i++) {
//            for (int j = i + 1; j < userIds.size(); j++) {
//                long userId1 = userIds.get(i);
//                long userId2 = userIds.get(j);
//                // 生成唯一的键来表示用户 ID 对
//                String pairKey = userId1 < userId2 ? userId1 + "-" + userId2 : userId2 + "-" + userId1;
//                if (!computedPairs.contains(pairKey)) {
//                    double similarityValue = similarity.userSimilarity(userId1, userId2);
//                    System.out.printf("用户 %d 与用户 %d 的相似度: %.4f%n", userId1, userId2, similarityValue);
//                    computedPairs.add(pairKey);
//                }
//            }
//        }
//        //获取用户邻居
//        UserNeighborhood userNeighborhood = new NearestNUserNeighborhood(2, similarity, dataModel);
//
//        //构建推荐器
//        Recommender recommender = new GenericUserBasedRecommender(dataModel, userNeighborhood, similarity);
//        //推荐2个
//        long targetUserId = userId.longValue();
//        System.out.println("userNeighborhood");
//        System.out.println(Arrays.toString(userNeighborhood.getUserNeighborhood(targetUserId)));
//        System.out.println("userId: " + targetUserId);
//        List<RecommendedItem> recommendedItems = recommender.recommend(targetUserId, Math.toIntExact(postsMapper.selectCount(null)));
//        List<Long> itemIds = recommendedItems.stream().map(RecommendedItem::getItemID).collect(Collectors.toList());
//        List<PostCardVO> recommendedTorrents = new ArrayList<>();
//        for (Long itemId : itemIds) {
//            System.out.println(itemId);
//            Posts post = postMapper.selectById(itemId);
//            if (post != null) {
//                PostCardVO vo = convertToCardVO(post);
//                recommendedTorrents.add(vo);
//            }
//        }
//        return recommendedTorrents;
//    }


    private DataModel createDataModel(List<UserPostRating> userArticleOperations) {
        FastByIDMap<PreferenceArray> fastByIdMap = new FastByIDMap<>();
        Map<Long, List<UserPostRating>> map = userArticleOperations.stream().collect(Collectors.groupingBy(UserPostRating::getUserId));
        Collection<List<UserPostRating>> list = map.values();
        for(List<UserPostRating> userPreferences : list){
            GenericPreference[] array = new GenericPreference[userPreferences.size()];
            for(int i = 0; i < userPreferences.size(); i++){
                UserPostRating userPreference = userPreferences.get(i);
                GenericPreference item = new GenericPreference(userPreference.getUserId(), userPreference.getPostId(), userPreference.getValue());
                array[i] = item;
            }
            fastByIdMap.put(array[0].getUserID(), new GenericUserPreferenceArray(Arrays.asList(array)));
        }
        return new GenericDataModel(fastByIdMap);
    }
}
